home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d2 / stepdos.arc / STEPDOS.ASM < prev    next >
Assembly Source File  |  1988-02-20  |  68KB  |  2,511 lines

  1. ;
  2. ;       ***********************************************************
  3. ;       *                                                         *
  4. ;       *                   S  T  E  P  D  O  S                   *
  5. ;       *                                                         *
  6. ;       *                        Rev 1.0                          *
  7. ;       *                                                         *
  8. ;       *                      Nov 7, 1987                        *
  9. ;       *                                                         *
  10. ;       *               Mike Parker - CIS 70270,161               *
  11. ;       *                                                         *
  12. ;       *  This program allows you to step through the execution  *
  13. ;       *  of another program by intercepting all calls to DOS    *
  14. ;       *  INT 21H. A window will pop up displaying all register  *
  15. ;       *  values and a short description of the DOS function     *
  16. ;       *  being called. Program execution will continue when     *
  17. ;       *  you press a key. You can optionally break again after  *
  18. ;       *  the DOS function completes so you can see the result   *
  19. ;       *  code in the AX register along with important flags.    *
  20. ;       *                                                         *
  21. ;       ***********************************************************
  22. ;
  23. ; To run, type STEPDOS <filename>
  24. ;  where <filename> is the full pathname of an EXE or COM file.
  25. ;
  26.  
  27.         PAGE    60,132
  28.         TITLE   'Step DOS Calls'
  29.         NAME    STEPDOS
  30.  
  31.  
  32. TESTING    EQU    0
  33.  
  34. BG         EQU    10H               ; BG sets background color (10h = BLUE)
  35.  
  36. BLACK      EQU    00H + BG
  37. BLUE       EQU    01H + BG
  38. GREEN      EQU    02H + BG
  39. CYAN       EQU    03H + BG
  40. RED        EQU    04H + BG
  41. MAGENTA    EQU    05H + BG
  42. BROWN      EQU    06H + BG
  43. WHITE      EQU    07H + BG
  44. GRAY       EQU    08H + BG
  45. LTBLUE     EQU    09H + BG
  46. LTGREEN    EQU    0AH + BG
  47. LTCYAN     EQU    0BH + BG
  48. LTRED      EQU    0CH + BG
  49. LTMAGENTA  EQU    0DH + BG
  50. YELLOW     EQU    0EH + BG
  51. HIWHITE    EQU    0FH + BG
  52. ;
  53. CR         EQU    13
  54. LF         EQU    10
  55. BIGR       EQU    1352H             ; 'R' key
  56. SMALLR     EQU    1372H             ; 'r'
  57. BIGS       EQU    1F53H             ; 'S' key
  58. SMALLS     EQU    1F73H             ; 's'
  59. ESCAPE     EQU    011BH
  60. HOME       EQU    4700H
  61. UPARROW    EQU    4800H
  62. PGUP       EQU    4900H
  63. LEFTARROW  EQU    4B00H
  64. RIGHTARROW EQU    4D00H
  65. XEND       EQU    4F00H
  66. DOWNARROW  EQU    5000H
  67. PGDN       EQU    5100H
  68. ;
  69. BLANK      EQU    32
  70. BRDROW     EQU    205
  71. BRDCOL     EQU    186
  72. ULC        EQU    201
  73. URC        EQU    187
  74. LLC        EQU    200
  75. LRC        EQU    188
  76. ;
  77. REGBX      EQU    00                ; offsets on saved register stack
  78. REGCX      EQU    02
  79. REGDX      EQU    04
  80. REGDI      EQU    06
  81. REGSI      EQU    08
  82. REGBP      EQU    10
  83. REGES      EQU    12
  84. REGFL      EQU    14
  85. ;
  86. IF TESTING
  87. INT21OFF   EQU    0e0h*4            ; during testing an unused INT is used
  88. ELSE
  89. INT21OFF   EQU    21h*4
  90. ENDIF
  91.  
  92. Code    SEGMENT PUBLIC PARA 'CODE'
  93.  
  94.         ASSUME  CS:Code, DS:Code
  95.  
  96. Main:                               ; starting point
  97.         mov     DI,DS
  98.         mov     BX,2
  99.         mov     SI,[BX]             ; paragraphs of memory in system from PSP
  100.         sub     SI,DI               ; paragraphs beyond segment
  101.         cmp     SI,1000h            ; more than 64K available ?
  102.         jb      main_1
  103.         mov     SI,1000h            ; yes, only use 64K
  104. main_1:
  105.         add     SI,DI               ; si = DS + number paragraphs in DS
  106.         mov     BX,ES               ; bx = PSP base
  107.         sub     BX,SI
  108.         neg     BX                  ; bx = number of paragraphs needed
  109.         mov     AH,4ah              ; modify memory block size
  110.         int     21h
  111. ;
  112. ; Copy command line from PSP to local area
  113. ;
  114.         mov     AX,CS
  115.         mov     ES,AX               ; change ES to be local area
  116. ;
  117.         mov     SI,80h
  118.         mov     CL,[SI]             ; get command line character count
  119.         or      CL,CL               ; zero char count in cmd line?
  120.         jnz     notzcl
  121.         mov     AX,CS
  122.         mov     DS,AX
  123.         mov     DX,OFFSET Umsg
  124.         mov     AH,9
  125.         int     21h
  126.         jmp     exit
  127. notzcl:
  128.         xor     CH,CH
  129.         inc     SI
  130.         mov     DI,OFFSET PSPstr
  131. rep     movsb                       ; copy command line
  132.         xor     AL,AL
  133.         stosb                       ; <NULL> terminator at end
  134. ;
  135.         mov     BX,002ch
  136.         mov     BX,[BX]             ; get segment addr of environment from PSP
  137. ;
  138.         mov     AX,CS
  139.         mov     DS,AX
  140.         mov     SegEnv,BX           ; save in EXEC control block
  141. ;
  142.         mov     DX,OFFSET INITmsg
  143.         mov     AH,9
  144.         int     21h
  145. ;
  146. ; Calculate starting address on screen for window
  147. ;
  148.         mov     BX,OFFSET W1        ; window parameters
  149.         mov     AX,[BX].leftrow
  150.         mul     BytesPL             ; multiply by bytes per line
  151.         mov     CX,[BX].leftcol
  152.         shl     CX,1                ; times 2 for attribute byte
  153.         add     AX,CX
  154.         mov     SI,AX               ; starting physical address of window
  155.         mov     [BX].startmem,AX    ; save it for later
  156. ;
  157. ; Calculate size of window in bytes to allocate memory
  158. ;
  159.         mov     AX,[BX].rightcol
  160.         inc     AX
  161.         sub     AX,[BX].leftcol
  162.         mov     [BX].xwidth,AX
  163.         mov     CX,[BX].rightrow
  164.         inc     CX
  165.         sub     CX,[BX].leftrow
  166.         mov     [BX].height,CX
  167.         mul     CL                  ; AX = nbr of bytes of screen area
  168.         shl     AX,1                ; times 2 to get attributes also
  169. ;
  170. ; Do DOS call to allocate memory
  171. ;
  172.         mov     CL,4
  173.         shr     AX,CL               ; divide by 16 to get # paragraphs
  174.         inc     AX                  ; handle any remainder
  175.         mov     BX,AX
  176.         mov     AH,48h              ; 'allocate memory' DOS call
  177.         int     21h
  178.         mov     Winseg,AX           ; save returned segment
  179.         jnc     cpynam
  180.         mov     DX,OFFSET Memerr    ; ERROR - display string
  181.         mov     AH,9
  182.         int     21h
  183.         jmp     exit                ;  and terminate
  184. ;
  185. ; Copy target program name
  186. ;
  187. cpynam:
  188.         mov     SI,OFFSET PSPstr + 1
  189.         mov     DI,OFFSET Filename
  190.         xor     CX,CX               ; zero char count
  191. fnlp:
  192.         cmp     BYTE PTR [SI],' '   ; look for <SP>
  193.         jz      fndn
  194.         cmp     BYTE PTR [SI],00    ;  or <NULL> terminator
  195.         jz      fndn
  196.         movsb
  197.         inc     CX                  ; count number of filename char's
  198.         jmp     fnlp
  199. fndn:
  200.         or      CX,CX
  201.         jnz     gotfn
  202.         mov     DX,OFFSET Findmsg   ; error if zero filename length
  203.         mov     AH,9
  204.         int     21h
  205.         jmp     freemem
  206. gotfn:
  207.         xor     AL,AL
  208.         stosb
  209.         mov     FNsize,CX
  210. ;
  211. ; Copy command line string
  212. ; SI -> first parameter after filename
  213. ;
  214.         mov     DI,OFFSET CLstr + 1
  215.         xor     CX,CX               ; zero char count
  216. cllp:
  217.         cmp     BYTE PTR [SI],00    ; look for <NULL> terminator
  218.         jz      dncl
  219.         movsb
  220.         inc     CX                  ; count number of cmd line char's
  221.         jmp     cllp
  222. dncl:
  223.         xor     AL,AL               ; store <NULL>
  224.         stosb
  225.         mov     AL,CR               ;  and <CR>
  226.         stosb
  227.         mov     CLstr,CL            ; store cmd line count
  228. ;
  229. ; Build EXEC control block
  230. ;
  231.         mov     SegCmd,OFFSET CLstr
  232.         mov     SegCmd+2,DS
  233.         mov     FCBptr1,OFFSET FCB1
  234.         mov     FCBptr1+2,DS
  235.         mov     FCBptr2,OFFSET FCB2
  236.         mov     FCBptr2+2,DS
  237. ;
  238. ; Parse first parameter
  239. ;
  240.         mov     SI,OFFSET CLstr + 1
  241.         mov     DI,OFFSET FCB1
  242.         mov     AL,01               ; scan past separators
  243.         mov     AH,29h
  244.         int     21h
  245. ;
  246. ; Parse second parameter
  247. ;
  248.         mov     DI,OFFSET FCB2
  249.         mov     AL,01               ; scan past separators
  250.         mov     AH,29h
  251.         int     21h
  252. ;
  253. ; Check for '.' in target program filename
  254. ;
  255.         mov     DI,OFFSET Filename
  256.         mov     CX,FNsize           ; get program filename size
  257.         mov     AL,'.'
  258. repne   scasb
  259.         jz      fndext
  260. ;
  261. ; No extention found, try appending '.COM'
  262. ;
  263.         mov     SI,OFFSET COMstr
  264.         mov     DI,OFFSET Filename
  265.         add     DI,FNsize
  266.         mov     CX,4
  267. rep     movsb
  268. ;
  269. ; Try to OPEN the target program to see if it exists before we change
  270. ; the Int 21h vector and EXEC it.
  271. ;
  272.         mov     AH,3dh
  273.         mov     AL,00               ; access code
  274.         mov     DX,OFFSET Filename
  275.         int     21h
  276.         jnc     clsfile             ; jump if file found
  277. ;
  278. ; OPEN with '.COM' extention failed, try appending '.EXE'
  279. ;
  280.         mov     SI,OFFSET EXEstr
  281.         mov     DI,OFFSET Filename
  282.         add     DI,FNsize
  283.         mov     CX,4
  284. rep     movsb
  285. ;
  286. ; Try to OPEN the '.EXE' version of the file
  287. ;
  288. fndext:
  289.         mov     AH,3dh
  290.         mov     AL,00               ; access code
  291.         mov     DX,OFFSET Filename
  292.         int     21h
  293.         jnc     clsfile
  294.         mov     DX,OFFSET Findmsg   ; not found
  295.         mov     AH,9
  296.         int     21h
  297.         jmp     freemem
  298. ;
  299. ; Found the file, now close it and do EXEC function
  300. ;
  301. clsfile:
  302.         mov     BX,AX               ; move file handle
  303.         mov     AH,3eh
  304.         int     21h
  305. ;
  306. ; Redirect INT 21h
  307. ;
  308. redirect:
  309.         push    ES
  310.         cli
  311.         mov     AX,0
  312.         mov     ES,AX
  313.         mov     AX,OFFSET New21
  314.         xchg    AX,ES:[INT21OFF]
  315.         mov     Save21,AX
  316.         mov     AX,CS
  317.         xchg    AX,ES:[INT21OFF+2]
  318.         mov     Save21+2,AX
  319.         sti
  320.         pop     ES
  321. ;
  322. ; Execute target program
  323. ;
  324.         mov     DX,OFFSET Filename
  325.         mov     BX,OFFSET Param_Block
  326.         mov     AH,4bh
  327.         mov     AL,0
  328.         mov     SP,OFFSET Tstack
  329.         int     21h
  330.         jnc     execdn
  331. ;
  332. ; Failed to execute target program. Display message and quit
  333. ;
  334.         mov     AX,CS
  335.         mov     DS,AX
  336.         mov     DX,OFFSET Execmsg
  337.         mov     AH,9
  338.         int     21h
  339. ;
  340. execdn:
  341.         mov     AX,CS               ; restore segment registers
  342.         mov     DS,AX
  343.         mov     ES,AX
  344.         mov     SS,AX
  345.         mov     SP,OFFSET Pstack
  346. ;
  347. ; Restore INT 21h vector
  348. ;
  349.         cli
  350.         mov     AX,0
  351.         mov     ES,AX
  352.         mov     AX,Save21
  353.         mov     ES:[INT21OFF],AX
  354.         mov     AX,Save21+2
  355.         mov     ES:[INT21OFF+2],AX
  356.         sti
  357. ;
  358. ; Free allocated memory from window save area
  359. ;
  360. freemem:
  361.         mov     ES,Winseg
  362.         mov     AH,49h
  363.         int     21h
  364. exit:
  365.         mov     AH,4ch              ; terminate process
  366.         mov     AL,00
  367.         int     21h                 ; won't return
  368.  
  369. ;
  370. ; INT 21h will be redirected to here
  371. ;
  372. New21:
  373.         push    AX                  ; use USERS'S stack for first 2 words
  374.         push    DS
  375. ;
  376.         mov     AX,CS               ; now switch to internal stack
  377.         mov     DS,AX
  378.         mov     SSsave,SS
  379.         mov     SPsave,SP
  380.         mov     SS,AX
  381.         mov     SP,OFFSET Pstack
  382. ;
  383.         pushf
  384.         push    ES
  385.         push    BP
  386.         push    SI
  387.         push    DI
  388.         push    DX
  389.         push    CX
  390.         push    BX
  391.         mov     BP,SP               ; save base pointer to display reg's
  392.         mov     ES,AX
  393.         mov     AL,Run_Flg
  394.         test    AL,0ffh             ; should we stop and display?
  395.         jnz     runit
  396.         jmp     norun               ; no, restore registers and leave
  397. runit:
  398.         cld                         ; clear direction flag for string operations
  399.         call    Get_User_Regs       ; recover registers left on user's stack
  400. ;
  401.         mov     AL,Skip_Flg
  402.         test    AL,0ffh             ; skip certain functions?
  403.         jz      noskip              ; no, continue
  404.         mov     AX,AXsave           ; get USER's AX register with function code
  405.         cmp     AH,Skip_Typ         ; compare upper half to type to skip
  406.         jnz     clrskip
  407.         jmp     norun               ; don't want to break on this one again
  408. clrskip:
  409.         mov     AL,00               ; skip flag was set but this is new
  410.         mov     Skip_Flg,AL         ;  function, so break from now on
  411. noskip:
  412.         call    Open_Window
  413.         call    Show_Regs
  414.         call    Show_Help
  415.         call    Disp_Text           ; Display description string of DOS function
  416. ;
  417.         call    Get_Key             ; wait for a key pressed
  418.         call    Disp_Key            ; dispatch to key handler
  419.         call    Close_Window
  420. norun:
  421.         pop     BX
  422.         pop     CX
  423.         pop     DX
  424.         pop     DI
  425.         pop     SI
  426.         pop     BP
  427.         pop     ES
  428.         popf
  429.         mov     SP,SPsave
  430.         mov     SS,SSsave
  431.         pop     DS
  432.         pop     AX
  433.  
  434. IFE TESTING
  435.         pushf
  436.         call    CS:[DWORD PTR Save21]
  437. ENDIF
  438.  
  439.         push    AX                  ; use USERS'S stack for first 2 words
  440.         push    DS
  441. ;
  442.         mov     AX,CS               ; now switch to internal stack
  443.         mov     DS,AX
  444.         mov     SSsave,SS
  445.         mov     SPsave,SP
  446.         mov     SS,AX
  447.         mov     SP,OFFSET Pstack
  448. ;
  449.         pushf
  450.         push    ES
  451.         push    BP
  452.         push    SI
  453.         push    DI
  454.         push    DX
  455.         push    CX
  456.         push    BX
  457.         mov     BP,SP               ; save base pointer to display reg's
  458.         mov     ES,AX
  459.         cld                         ; clear direction flag for string operations
  460.         call    Get_User_Regs       ; recover registers left on user's stack
  461.         xor     AL,AL
  462.         xchg    AL,Ret_Flg          ; read value and clear flag for next time
  463.         test    AL,0ffh             ; is flag set to display return value?
  464.         jz      nostop
  465. ;
  466.         call    Open_Window
  467.         call    Show_Regs
  468.         call    Disp_Ret            ; display return code in AX and flags
  469.         call    Get_Key             ; wait for a key pressed
  470.         call    Close_Window
  471. nostop:
  472.         pop     BX
  473.         pop     CX
  474.         pop     DX
  475.         pop     DI
  476.         pop     SI
  477.         pop     BP
  478.         pop     ES
  479.         popf
  480.         mov     SP,SPsave
  481.         mov     SS,SSsave
  482.         pop     DS
  483.         pop     AX
  484.         retf    2
  485.  
  486. ;
  487. ; Display return code in AX, carry and zero flags
  488. ;
  489. Disp_Ret:
  490.         mov     DX,OFFSET RCStr
  491.         mov     DI,14
  492.         mov     AX,AXsave
  493.         call    OutWord
  494. ;
  495.         mov     DX,OFFSET CFStr
  496.         mov     DI,13
  497.         add     DI,DX
  498.         mov     AL,'0'
  499.         test    FLsave,0001         ; carry flag is least significant bit
  500.         jz      dcy
  501.         inc     AL                  ; carry was set so change to '1'
  502. dcy:
  503.         mov     [DI],AL             ; store it in string
  504.         add     CX,0015h            ; move cursor position
  505.         mov     BX,OFFSET W1
  506.         mov     AH,HIWHITE
  507.         call    WPrint
  508. ;
  509.         mov     DX,OFFSET ZFStr
  510.         mov     DI,12
  511.         add     DI,DX
  512.         mov     AL,'0'
  513.         test    FLsave,0040h        ; test zero flag
  514.         jz      dzf
  515.         inc     AL                  ; zero was set so change to '1'
  516. dzf:
  517.         mov     [DI],AL             ; store it in string
  518.         add     CX,0010h            ; move cursor position
  519.         mov     BX,OFFSET W1
  520.         mov     AH,HIWHITE
  521.         call    WPrint
  522. ;
  523.         mov     CX,0816h            ; display some help
  524.         mov     DX,OFFSET HlpStr4
  525.         mov     AH,YELLOW
  526.         call    WPrint
  527.         ret
  528.  
  529. RCStr   db      'Return Code = XXXXH'
  530.         db      0
  531.  
  532. CFStr   db      'Carry Flag = X'
  533.         db      0
  534.  
  535. ZFStr   db      'Zero Flag = X'
  536.         db      0
  537.  
  538. ;
  539. ; Recover registers on USER'S stack
  540. ;
  541. Get_User_Regs:
  542.         push    ES
  543.         les     BX,Ssave
  544.         mov     AX,ES:[BX]          ; get DS
  545.         mov     DSsave,AX
  546.         mov     AX,ES:[BX+2]        ; get AX
  547.         mov     AXsave,AX
  548.         mov     AX,ES:[BX+4]        ; get IP
  549.         mov     IPsave,AX
  550.         mov     AX,ES:[BX+6]        ; get CS
  551.         mov     CSsave,AX
  552.         mov     AX,[BP+REGFL]       ; get FLAGS off local stack
  553.         mov     FLsave,AX
  554.         pop     ES
  555.         ret
  556.  
  557. ;
  558. ; Display register names in window
  559. ;
  560. Show_Regs:
  561.         mov     BX,OFFSET W1        ; window
  562.         mov     CX,0001h            ; cursor position - row, col
  563.         mov     DX,OFFSET RegStr1   ; message address
  564.         mov     AH,YELLOW           ; attribute
  565.         call    WPrint
  566. ;
  567.         add     CX,0100h            ; go down one row
  568.         mov     DX,OFFSET RegStr2
  569.         mov     AH,WHITE
  570.         call    WPrint
  571. ;
  572. ; Display register values
  573. ;
  574.         add     CX,0100h            ; down a row
  575.         mov     AX,AXsave           ; get user's AX
  576.         call    Whexwd              ; display hex word
  577. ;
  578.         push    BP                  ; save base pointer for string display
  579.         mov     DX,6                ; number of registers to show this loop
  580. disreg:
  581.         add     CX,0005h            ; move to next register field
  582.         mov     AX,[BP]
  583.         call    Whexwd              ; display hex word
  584.         add     BP,2
  585.         dec     DX
  586.         jnz     disreg
  587. ;
  588.         add     CX,0005h            ; move to next register field
  589.         mov     AX,SPsave           ; display SP
  590.         add     AX,4                ; add for 2 pushes we did
  591.         call    Whexwd
  592. ;
  593.         add     CX,0005h            ; move to next register field
  594.         mov     AX,DSsave           ; display DS
  595.         call    Whexwd
  596. ;
  597.         add     CX,0005h            ; display ES
  598.         mov     AX,[BP]
  599.         call    Whexwd
  600. ;
  601.         add     CX,0005h
  602.         mov     AX,SSsave           ; display SS
  603.         call    Whexwd
  604. ;
  605.         add     CX,0005h
  606.         mov     AX,CSsave           ; display CS
  607.         call    Whexwd
  608. ;
  609.         add     CX,0005h
  610.         mov     AX,IPsave           ; display IP
  611.         call    Whexwd
  612. ;
  613.         add     CX,0005h
  614.         mov     AX,FLsave           ; display FLAGS
  615.         call    Whexwd
  616.         pop     BP                  ; restore base pointer so display routines
  617.                                     ;  can use it
  618.         ret
  619.  
  620. ;
  621. ; Display HELP in Window
  622. ;
  623. Show_Help:
  624.         mov     CX,0801h            ; cursor position - row, col
  625.         mov     AH,LTRED            ; attribute for char
  626.         mov     AL,'S'
  627.         call    WChar               ; write one character with attribute
  628. ;
  629.         add     CX,0001h            ; add 1 to column number
  630.         mov     DX,OFFSET HlpStr1   ; message address
  631.         mov     AH,WHITE
  632.         call    WPrint
  633. ;
  634.         add     CX,0017h            ; move column number
  635.         mov     AH,LTRED            ; attribute for char
  636.         mov     AL,'R'
  637.         call    WChar               ; write one character with attribute
  638. ;
  639.         add     CX,0001h            ; move column number
  640.         mov     DX,OFFSET HlpStr2
  641.         mov     AH,WHITE
  642.         call    WPrint
  643. ;
  644.         add     CX,000dh
  645.         mov     AH,LTRED
  646.         mov     AL,'E'
  647.         call    WChar
  648. ;
  649.         add     CX,0001h
  650.         mov     AH,LTRED
  651.         mov     AL,'S'
  652.         call    WChar
  653. ;
  654.         add     CX,0001h
  655.         mov     AH,LTRED
  656.         mov     AL,'C'
  657.         call    WChar
  658. ;
  659.         add     CX,0001h
  660.         mov     DX,OFFSET HlpStr3
  661.         mov     AH,WHITE
  662.         call    WPrint
  663.         ret
  664.  
  665. ;
  666. ; HextoDec converts a word in AX to an ASCII string
  667. ; Entry:
  668. ;      AX = word to convert
  669. ; Exit:
  670. ;      SI = Pointer to last two character of ASCII string in 'Astr'
  671. ;
  672. HextoDec:
  673.          push   AX
  674.          push   CX
  675.          push   DX
  676.          push   DI
  677. ;
  678.          mov    DI,OFFSET Astr
  679.          mov    CX,10000
  680.          xor    DX,DX
  681.          div    CX                  ; num / 10000
  682.          add    AL,'0'
  683.          stosb
  684.          mov    AX,DX
  685.          mov    CX,1000
  686.          xor    DX,DX
  687.          div    CX                  ; num / 1000
  688.          add    AL,'0'
  689.          stosb
  690.          mov    AX,DX
  691.          mov    CX,100
  692.          xor    DX,DX
  693.          div    CX                  ; num / 100
  694.          add    AL,'0'
  695.          stosb
  696.          mov    AX,DX
  697.          mov    CX,10
  698.          xor    DX,DX
  699.          div    CX                  ; num / 10
  700.          add    AL,'0'
  701.          stosb
  702.          mov    AX,DX
  703.          add    AL,'0'
  704.          stosb
  705.          xor    AL,AL               ; <NULL> terminator in string
  706.          stosb
  707.          sub    DI,3                ; back up pointer
  708.          mov    SI,DI
  709. ;
  710.          pop    DI
  711.          pop    DX
  712.          pop    CX
  713.          pop    AX
  714.          ret
  715.  
  716. ;
  717. ; Display the text description of the current DOS function code
  718. ;
  719. Disp_Text:
  720.         mov     AX,AXsave           ; get user's function code
  721.         cmp     AH,63h              ; is it in range?
  722.         jnb     not_fnd             ; jump if no
  723.         mov     DI,OFFSET FCtbl
  724.         mov     CX,LENFC / 6        ; number of entries
  725. cmpdt:
  726.         cmp     AH,[DI+1]           ; is this the right function?
  727.         jz      dtexec
  728.         add     DI,6                ; no, point to next
  729.         loop    cmpdt
  730. not_fnd:
  731.         mov     DX,OFFSET STRUN
  732.         call    Disp_Str
  733.         ret
  734.  
  735. dtexec:
  736.         mov     DX,[DI+2]           ; get pointer to string
  737.         call    [WORD PTR DI+4]     ; go to display routine
  738.         ret
  739.  
  740. ;
  741. ; Display string of DOS function code description
  742. ;
  743. ; Entry:
  744. ;       DX = pointer to string
  745. ;
  746. Disp_Str:
  747.         mov     CX,0501h
  748.         mov     BX,OFFSET W1
  749.         mov     AH,HIWHITE
  750.         call    WPrint
  751.         ret
  752.  
  753. ;
  754. ; Only one string must be inserted.
  755. ; It is pointed to by user's DS:DX.
  756. ; Entry:
  757. ;      DX = text string containing description of function call
  758. ;      DI = offset within local string (DX) to put user's (DS:DX)
  759. ;      CX = max length before you will hit right side of Window
  760. ;
  761. One_String:
  762.         add     DI,DX
  763.         push    DS
  764.         mov     DS,DSsave
  765.         mov     SI,[BP+REGDX]       ; get USER's DS:DX value
  766. rep     movsb                       ; copy user's memory to text string
  767.         pop     DS
  768.         call    Disp_Str
  769.         ret
  770.  
  771. ;
  772. ; Convert users's DS and DX to ASCII, imbed them in target string
  773. ; Entry:
  774. ;      DX = pointer to string
  775. ;      DI = offset where to put converted DS:DX
  776. ;
  777. OutDSDX:
  778.         add     DI,DX
  779.         mov     AX,DSsave           ; get user's DS
  780.         call    Shexwrd
  781.         inc     DI                  ; skip past ':'
  782.         mov     AX,[BP+REGDX]       ; get user's DX
  783.         call    Shexwrd
  784.         call    Disp_Str
  785.         ret
  786.  
  787. ;
  788. ; Convert word in AX to ASCII, imbed it in target string
  789. ; Entry:
  790. ;      AX = word to convert
  791. ;      DX = pointer to string
  792. ;      DI = offset where to put converted AX
  793. ;
  794. OutWord:
  795.         add     DI,DX
  796.         call    Shexwrd
  797.         call    Disp_Str
  798.         ret
  799.  
  800. ;
  801. ; Convert 'AL' to ASCII and imbed it in target string
  802. ; Entry:
  803. ;      DX = target string
  804. ;      DI = offset to put converted 'AL'
  805. ;      AL = value to convert
  806. ;
  807. OutByte:
  808.         add     DI,DX
  809.         call    Shexbyt
  810.         call    Disp_Str
  811.         ret
  812.  
  813. ;
  814. ; Routines to build string for display - some values need to be filled in
  815. ;
  816. ; Entry:
  817. ;       DX = pointer to string
  818. ;
  819. Disp_02:
  820. Disp_04:
  821. Disp_05:
  822.         mov     DI,DX
  823.         add     DI,22               ; offset this many into string
  824.         mov     AX,[BP+REGDX]       ; DL register has char to output
  825.         call    Shexbyt             ; convert it to ASCII
  826.         mov     [DI+8],AL           ; show hex byte
  827.         call    Disp_Str
  828.         ret
  829.  
  830. ;
  831. ; Direct Keyboard/Display I/O
  832. ;
  833. Disp_06:
  834.         call    Disp_Str
  835.         mov     AX,[BP+REGDX]       ; DL register has I/O type
  836.         mov     DX,OFFSET STR06I
  837.         cmp     AL,0ffh             ; input character?
  838.         jz      d06io
  839.         mov     DX,OFFSET STR02     ; no, output character in 'DL'
  840.         mov     DI,DX
  841.         add     DI,22               ; offset this many into string
  842.         call    Shexbyt             ; convert it to ASCII
  843.         mov     [DI+8],AL           ; show hex byte
  844. d06io:
  845.         add     CX,0015h
  846.         mov     BX,OFFSET W1
  847.         mov     AH,HIWHITE
  848.         call    WPrint
  849.         ret
  850.  
  851. ;
  852. ; Display String
  853. ; Entry:
  854. ;      DX = pointer to string
  855. ;
  856. Disp_09:
  857. Disp_39:
  858. Disp_3a:
  859. Disp_3b:
  860. Disp_3c:
  861. Disp_3d:
  862. Disp_41:
  863. Disp_5a:
  864. Disp_5b:
  865.         mov     DI,18               ; offset where (DS:DX) goes within string
  866.         mov     cx,52               ; max number of char's to fit in window
  867.         call    One_String
  868.         ret
  869.  
  870. Disp_0a:
  871. Disp_23:
  872.         mov     DI,27
  873.         call    OutDSDX
  874.         ret
  875.  
  876. ;
  877. ; Clear Keyboard and Do Function
  878. ;
  879. Disp_0c:
  880.         mov     DI,31
  881.         mov     AX,AXsave           ; AL register has function number
  882.         call    OutByte
  883.         ret
  884.  
  885. ;
  886. ; Select Disk
  887. ;
  888. Disp_0e:
  889.         mov     DI,12
  890.         mov     AX,[BP+REGDX]       ; DL register has char to output
  891.         call    OutByte
  892.         ret
  893.  
  894. ;
  895. ; Open File Using FCB
  896. ;
  897. Disp_0f:
  898.         mov     DI,23
  899.         call    OutDSDX
  900.         ret
  901.  
  902. ;
  903. ; Close File Using FCB
  904. ;
  905. Disp_10:
  906.         mov     DI,24
  907.         call    OutDSDX
  908.         ret
  909.  
  910. ;
  911. ; Search For First Matching File Using FCB
  912. ;
  913. Disp_11:
  914.         mov     DI,44
  915.         call    OutDSDX
  916.         ret
  917.  
  918. ;
  919. ; Search For Next Matching File Using FCB
  920. ;
  921. Disp_12:
  922.         mov     DI,43
  923.         call    OutDSDX
  924.         ret
  925.  
  926. ;
  927. ; Delete File Using FCB
  928. ; Create File Using FCB
  929. ; Rename File Using FCB
  930. ;
  931. Disp_13:
  932. Disp_16:
  933. Disp_17:
  934.         mov     DI,25
  935.         call    OutDSDX
  936.         ret
  937.  
  938. ;
  939. ; Read Sequential File Record Using FCB
  940. ;
  941. Disp_14:
  942.         mov     DI,41
  943.         call    OutDSDX
  944.         ret
  945.  
  946. ;
  947. ; Write Sequential File Record Using FCB
  948. ;
  949. Disp_15:
  950.         mov     DI,42
  951.         call    OutDSDX
  952.         ret
  953.  
  954. ;
  955. ; Set Disk Transfer Address
  956. ;
  957. Disp_1a:
  958.         mov     DI,29
  959.         call    OutDSDX
  960.         ret
  961.  
  962. ;
  963. ; Get FAT Information For Drive
  964. ;
  965. Disp_1c:
  966.         mov     DI,30
  967.         mov     AX,[BP+REGDX]       ; DL register has drive number
  968.         call    OutByte
  969.         ret
  970.  
  971.  
  972. ;
  973. ; Read Random File Record Using FCB
  974. ; Set Random Record Field Using FCB
  975. ;
  976. Disp_21:
  977. Disp_24:
  978.         mov     DI,37
  979.         call    OutDSDX
  980.         ret
  981.  
  982. ;
  983. ; Write Random File Record Using FCB
  984. ;
  985. Disp_22:
  986.         mov     DI,38
  987.         call    OutDSDX
  988.         ret
  989.  
  990. ;
  991. ; Set Interrupt Vector
  992. ;
  993. Disp_25:
  994.         mov     DI,DX
  995.         add     DI,21
  996.         mov     AX,AXsave           ; AL has interrupt vector number
  997.         call    Shexbyt
  998.         mov     DI,28
  999.         call    OutDSDX
  1000.         ret
  1001.  
  1002. ;
  1003. ; Create New Program Segment
  1004. ;
  1005. Disp_26:
  1006.         mov     DI,38
  1007.         mov     AX,[BP+REGDX]       ; get user's DX
  1008.         call    OutWord
  1009.         ret
  1010.  
  1011. ;
  1012. ; Read Random File Records
  1013. ;
  1014. Disp_27:
  1015.         mov     DI,DX
  1016.         add     DI,5
  1017.         mov     AX,[BP+REGCX]       ; CX register has record count
  1018.         call    Shexwrd
  1019.         mov     DI,44
  1020.         call    OutDSDX
  1021.         ret
  1022.  
  1023. ;
  1024. ; Write Random File Records
  1025. ;
  1026. Disp_28:
  1027.         mov     DI,DX
  1028.         add     DI,6
  1029.         mov     AX,[BP+REGCX]       ; CX register has record count
  1030.         call    Shexwrd
  1031.         mov     DI,45
  1032.         call    OutDSDX
  1033.         ret
  1034. ;
  1035. ; Parse Filename
  1036. ;
  1037. Disp_29:
  1038.         mov     DI,18               ; offset where (DS:SI) goes within string
  1039.         mov     cx,52               ; max number of char's to fit in window
  1040.         add     DI,DX
  1041.         push    DI                  ; save for scan later
  1042.         push    DS
  1043.         mov     DS,DSsave
  1044.         mov     SI,[BP+REGSI]       ; get USER's DS:SI value
  1045. rep     movsb                       ; copy user's memory to text string
  1046.         pop     DS
  1047. ;
  1048. ; look for <CR> in string and put <NULL> terminator there
  1049. ;
  1050.         pop     DI
  1051.         mov     AL,CR
  1052.         mov     cx,52
  1053. repne   scasb
  1054.         jnz     dpf
  1055.         dec     DI
  1056.         xor     AL,AL
  1057.         mov     [DI],AL
  1058. dpf:
  1059.         call    Disp_Str
  1060.         ret
  1061.  
  1062. ;
  1063. ; Set Date
  1064. ;
  1065. Disp_2b:
  1066.         mov     DI,DX
  1067.         add     DI,22
  1068.         mov     AX,[BP+REGDX]       ; DX register has month/day
  1069.         mov     AL,AH
  1070.         xor     AH,AH
  1071.         call    HextoDec            ; convert month
  1072.         movsb
  1073.         movsb
  1074.         inc     DI                  ; skip past '/'
  1075.         mov     AX,[BP+REGDX]
  1076.         xor     AH,AH
  1077.         call    HextoDec            ; convert day
  1078.         movsb
  1079.         movsb
  1080.         inc     DI                  ; skip past '/'
  1081.         mov     AX,[BP+REGCX]
  1082.         call    HextoDec            ; convert year
  1083.         movsb
  1084.         movsb
  1085.         call    Disp_Str
  1086.         ret
  1087.  
  1088. ;
  1089. ; Set Time
  1090. ;
  1091. Disp_2d:
  1092.         mov     DI,DX
  1093.         add     DI,33
  1094.         mov     AX,[BP+REGCX]       ; CX register has hours/minutes
  1095.         mov     AL,AH
  1096.         xor     AH,AH
  1097.         call    HextoDec            ; convert hours
  1098.         movsb
  1099.         movsb
  1100.         inc     DI                  ; skip past ':'
  1101.         mov     AX,[BP+REGCX]
  1102.         xor     AH,AH
  1103.         call    HextoDec            ; convert minutes
  1104.         movsb
  1105.         movsb
  1106.         inc     DI                  ; skip past ':'
  1107.         mov     AX,[BP+REGDX]       ; DX has seconds/hundreds of seconds
  1108.         mov     AL,AH
  1109.         xor     AH,AH
  1110.         call    HextoDec            ; convert seconds
  1111.         movsb
  1112.         movsb
  1113.         inc     DI                  ; skip past ':'
  1114.         mov     AX,[BP+REGDX]
  1115.         xor     AH,AH
  1116.         call    HextoDec            ; convert hundreds
  1117.         movsb
  1118.         movsb
  1119.         call    Disp_Str
  1120.         ret
  1121.  
  1122. ;
  1123. ; Set Disk Write Verification
  1124. ;
  1125. Disp_2e:
  1126.         mov     DI,DX
  1127.         add     DI,28
  1128.         mov     AX,AXsave           ; AL register has verify switch
  1129.         mov     SI,OFFSET OFFstr
  1130.         cmp     AL,00               ; AL = 0 means OFF
  1131.         jz      verptr
  1132.         mov     SI,OFFSET ONstr
  1133.         cmp     AL,01               ; AL = 1 means ON
  1134.         jz      verptr
  1135.         mov     SI,OFFSET Blanks3   ; unknown code
  1136. verptr:
  1137.         mov     CX,3
  1138. rep     movsb
  1139.         call    Disp_Str
  1140.         ret
  1141.  
  1142. ;
  1143. ; Get/Set Control-Break Status
  1144. ;
  1145. Disp_33:
  1146.         mov     AX,AXsave           ; AL register has get/set switch
  1147.         cmp     AL,01               ; AL = 1 for SET
  1148.         jz      setcbs
  1149.         cmp     AL,00               ; AL = 0 for GET
  1150.         jnz     unk33               ; jump if unknown code
  1151.         mov     DX,OFFSET STR33G
  1152. unk33:
  1153.         call    Disp_Str
  1154.         ret
  1155.  
  1156. setcbs:
  1157.         mov     DX,OFFSET STR33S    ; point to 'SET' string
  1158.         mov     DI,DX
  1159.         add     DI,25
  1160.         mov     AX,[BP+REGDX]       ; DL has set code
  1161.         mov     SI,OFFSET OFFstr
  1162.         cmp     AL,00               ; AL = 00 means OFF
  1163.         jz      gscbs
  1164.         mov     SI,OFFSET ONstr
  1165.         cmp     AL,01               ; AL = 01 means ON
  1166.         jz      gscbs
  1167.         mov     SI,OFFSET Blanks3
  1168. gscbs:
  1169.         mov     CX,3
  1170. rep     movsb
  1171.         call    Disp_Str
  1172.         ret
  1173.  
  1174. ;
  1175. ; Get Interrupt Vector
  1176. ;
  1177. Disp_35:
  1178.         mov     DI,21
  1179.         mov     AX,AXsave           ; AL has interrupt vector number
  1180.         call    OutByte
  1181.         ret
  1182.  
  1183. ;
  1184. ; Get Disk Free Space On Drive
  1185. ;
  1186. Disp_36:
  1187.         mov     DI,29
  1188.         mov     AX,[BP+REGDX]       ; DL register has drive code
  1189.         call    OutByte
  1190.         ret
  1191.  
  1192. ;
  1193. ; Close File Handle
  1194. ;
  1195. Disp_3e:
  1196.         mov     DI,18
  1197.         mov     AX,[BP+REGBX]       ; BX register has file handle
  1198.         call    OutWord
  1199.         ret
  1200.  
  1201. ;
  1202. ; Duplicate File Handle
  1203. ;
  1204. Disp_45:
  1205.         mov     DI,22
  1206.         mov     AX,[BP+REGBX]       ; BX register has file handle
  1207.         call    OutWord
  1208.         ret
  1209.  
  1210. ;
  1211. ; Read From File or Device
  1212. ;
  1213. Disp_3f:
  1214.         mov     DI,DX
  1215.         add     DI,5
  1216.         mov     AX,[BP+REGCX]       ; CX has number of bytes to read
  1217.         call    Shexwrd
  1218.         mov     DI,37
  1219.         mov     AX,[BP+REGBX]       ; BX has file handle
  1220.         call    OutWord
  1221.         ret
  1222.  
  1223. ;
  1224. ; Write To File or Device
  1225. ;
  1226. Disp_40:
  1227.         mov     DI,DX
  1228.         add     DI,6
  1229.         mov     AX,[BP+REGCX]       ; CX has number of bytes to read
  1230.         call    Shexwrd
  1231.         mov     DI,36
  1232.         mov     AX,[BP+REGBX]       ; BX has file handle
  1233.         call    OutWord
  1234.         ret
  1235.  
  1236. ;
  1237. ; Move File Pointer
  1238. ;
  1239. Disp_42:
  1240.         mov     DI,DX
  1241.         add     DI,17
  1242.         mov     AX,[BP+REGBX]       ; BX register has file handle
  1243.         call    Shexwrd
  1244.         add     DI,13
  1245.         mov     AX,[BP+REGCX]       ; CX has upper half of offset
  1246.         call    Shexwrd
  1247.         inc     DI                  ; skip past ':'
  1248.         mov     AX,[BP+REGDX]       ; CX has lower half of offset
  1249.         call    Shexwrd
  1250.         add     DI,7
  1251.         mov     AX,AXsave           ; AL has method code
  1252.         mov     SI,OFFSET BOFstr
  1253.         cmp     AL,00               ; beginning of file?
  1254.         jz      mvptr
  1255.         mov     SI,OFFSET CURstr
  1256.         cmp     AL,01               ; current location?
  1257.         jz      mvptr
  1258.         mov     SI,OFFSET EOFstr
  1259.         cmp     AL,02               ; end of file?
  1260.         jz      mvptr
  1261.         mov     SI,OFFSET Blanks17  ; unknown
  1262. mvptr:
  1263.         mov     cx,17               ; string length
  1264. rep     movsb
  1265.         call    Disp_Str
  1266.         ret
  1267.  
  1268. ;
  1269. ; Get/Set file attributes
  1270. ;
  1271. Disp_43:
  1272.         mov     AX,AXsave           ; user's AX has get/set flag
  1273.         cmp     AL,00               ; 'get' code?
  1274.         jz      fgptr
  1275.         cmp     AL,01               ; 'set' code?
  1276.         jz      fsptr
  1277.         call    Disp_Str            ; unknown code
  1278.         ret
  1279. fgptr:
  1280.         mov     DX,OFFSET STR43G    ; point to GET string
  1281.         jmp     SHORT faptr
  1282. ;
  1283. fsptr:
  1284.         mov     DX,OFFSET STR43S    ; point to SET string
  1285. faptr:
  1286.         mov     DI,18
  1287.         mov     cx,52               ; max number of char's to fit in window
  1288.         call    One_String
  1289.         ret
  1290.  
  1291. ;
  1292. ; I/O Control For Devices
  1293. ;
  1294. Disp_44:
  1295.         mov     AX,AXsave
  1296.         cmp     AL,00
  1297.         jz      jd440
  1298.         cmp     AL,01
  1299.         jz      jd441
  1300.         cmp     AL,02
  1301.         jz      jd442
  1302.         cmp     AL,03
  1303.         jz      jd443
  1304.         cmp     AL,04
  1305.         jz      jd444
  1306.         cmp     AL,05
  1307.         jz      jd445
  1308.         cmp     AL,06
  1309.         jz      jd446
  1310.         cmp     AL,07
  1311.         jz      jd447
  1312.         cmp     AL,08
  1313.         jz      jd448
  1314.         cmp     AL,11
  1315.         jz      jd4411
  1316.         call    Disp_Str            ; unknown code
  1317.         ret
  1318.  
  1319. jd440:  jmp     d440
  1320. jd441:  jmp     d441
  1321. jd442:  jmp     d442
  1322. jd443:  jmp     d443
  1323. jd444:  jmp     d444
  1324. jd445:  jmp     d445
  1325. jd446:  jmp     d446
  1326. jd447:  jmp     d447
  1327. jd448:  jmp     d448
  1328. jd4411: jmp     d4411
  1329.  
  1330. d440:
  1331.         mov     DX,OFFSET STR440    ; Get Info For Device
  1332.         mov     DI,20
  1333.         mov     AX,[BP+REGBX]       ; BX has file handle
  1334.         call    OutWord
  1335.         ret
  1336. ;
  1337. d441:
  1338.         mov     DX,OFFSET STR441    ; Set Info For Device
  1339.         mov     DI,DX
  1340.         add     DI,20
  1341.         mov     AX,[BP+REGBX]       ; BX has file handle
  1342.         call    Shexwrd
  1343.         mov     DI,29
  1344.         mov     AX,[BP+REGDX]       ; DX has device information
  1345.         call    OutWord
  1346.         ret
  1347. ;
  1348. d442:
  1349.         mov     DX,OFFSET STR442    ; Read From Drive Control Channel
  1350.         mov     DI,DX
  1351.         add     DI,5
  1352.         mov     AX,[BP+REGCX]       ; CX has byte count
  1353.         call    Shexwrd
  1354.         mov     DI,52
  1355.         mov     AX,[BP+REGBX]       ; BX has file handle
  1356.         call    OutWord
  1357.         ret
  1358. ;
  1359. d443:
  1360.         mov     DX,OFFSET STR443    ; Write To Drive Control Channel
  1361.         mov     DI,DX
  1362.         add     DI,6
  1363.         mov     AX,[BP+REGCX]       ; CX has byte count
  1364.         call    Shexwrd
  1365.         mov     DI,51
  1366.         mov     AX,[BP+REGBX]       ; BX has file handle
  1367.         call    OutWord
  1368.         ret
  1369. ;
  1370. d444:
  1371.         mov     DX,OFFSET STR444    ; Read From Control Channel of Drive
  1372.         mov     DI,DX
  1373.         add     DI,5
  1374.         mov     AX,[BP+REGCX]       ; CX has byte count
  1375.         call    Shexwrd
  1376.         mov     DI,47
  1377.         mov     AX,[BP+REGBX]       ; BL has drive
  1378.         call    OutByte
  1379.         ret
  1380. ;
  1381. d445:
  1382.         mov     DX,OFFSET STR445    ; Write To Control Channel of Drive
  1383.         mov     DI,DX
  1384.         add     DI,6
  1385.         mov     AX,[BP+REGCX]       ; CX has byte count
  1386.         call    Shexwrd
  1387.         mov     DI,46
  1388.         mov     AX,[BP+REGBX]       ; BL has drive
  1389.         call    OutByte
  1390.         ret
  1391. ;
  1392. d446:
  1393.         mov     DX,OFFSET STR446    ; Get Input Status of Device
  1394.         mov     DI,27
  1395.         mov     AX,[BP+REGBX]       ; BX has file handle
  1396.         call    OutWord
  1397.         ret
  1398. ;
  1399. d447:
  1400.         mov     DX,OFFSET STR447    ; Get Output Status of Device
  1401.         mov     DI,28
  1402.         mov     AX,[BP+REGBX]       ; BX has file handle
  1403.         call    OutWord
  1404.         ret
  1405. ;
  1406. d448:
  1407.         mov     DX,OFFSET STR448    ; Report Whether Device Has Removable Media
  1408.         mov     DI,22
  1409.         mov     AX,[BP+REGBX]       ; BX has file handle
  1410.         call    OutWord
  1411.         ret
  1412. ;
  1413. d4411:
  1414.         mov     DX,OFFSET STR4411   ; Set Retries For Device
  1415.         mov     DI,DX
  1416.         add     DI,23
  1417.         mov     AX,[BP+REGBX]       ; BX has file handle
  1418.         call    Shexwrd
  1419.         add     DI,5
  1420.         mov     AX,[BP+REGDX]       ; DX has retry count
  1421.         call    Shexwrd
  1422.         mov     DI,55
  1423.         mov     AX,[BP+REGCX]       ; CX has interval between tries
  1424.         call    OutWord
  1425.         ret
  1426.  
  1427. ;
  1428. ; Force Duplication of Handle
  1429. ;
  1430. Disp_46:
  1431.         mov     DI,DX
  1432.         add     DI,28
  1433.         mov     AX,[BP+REGBX]       ; BX has the existing file handle
  1434.         call    Shexwrd
  1435.         mov     DI,37
  1436.         mov     AX,[BP+REGCX]       ; CX has the second file handle
  1437.         call    OutWord
  1438.         ret
  1439.  
  1440. ;
  1441. ; Get Current Directory
  1442. ;
  1443. Disp_47:
  1444.         mov     DI,DX
  1445.         add     DI,31
  1446.         mov     AX,[BP+REGDX]       ; DL register has drive code
  1447.         call    Shexbyt
  1448.         add     DI,7
  1449.         mov     AX,DSsave
  1450.         call    Shexwrd
  1451.         inc     DI                  ; skip ':'
  1452.         mov     AX,[BP+REGSI]       ; get USER's DS:SI value
  1453.         call    Shexwrd
  1454.         call    Disp_Str
  1455.         ret
  1456.  
  1457. ;
  1458. ; Allocate Memory
  1459. ;
  1460. Disp_48:
  1461.         mov     DI,9
  1462.         mov     AX,[BP+REGBX]       ; BX has the memory requested in paragraphs
  1463.         call    OutWord
  1464.         ret
  1465.  
  1466. ;
  1467. ; Free Allocated Memory
  1468. ;
  1469. Disp_49:
  1470.         mov     DI,33
  1471.         mov     AX,[BP+REGES]       ; ES has the segment address
  1472.         call    OutWord
  1473.         ret
  1474.  
  1475. ;
  1476. ; Modify Memory Block
  1477. ;
  1478. Disp_4a:
  1479.         mov     DI,DX
  1480.         add     DI,31
  1481.         mov     AX,[BP+REGES]       ; ES has the segment address
  1482.         call    Shexwrd
  1483.         mov     DI,43
  1484.         mov     AX,[BP+REGBX]       ; BX has size in paragraphs
  1485.         call    OutWord
  1486.         ret
  1487.  
  1488. ;
  1489. ; Load or Exececute Program
  1490. ; Find First Matching File
  1491. ;
  1492. Disp_4b:
  1493. Disp_4e:
  1494.         mov     DI,29               ; offset where (DS:DX) goes within string
  1495.         mov     cx,41               ; max number of char's to fit in window
  1496.         call    One_String
  1497.         ret
  1498.  
  1499. ;
  1500. ; Terminate Process with Return Code
  1501. ;
  1502. Disp_4c:
  1503.         mov     DI,35
  1504.         mov     AX,Axsave           ; AL register return code
  1505.         call    OutByte
  1506.         ret
  1507.  
  1508. ;
  1509. ; Rename File
  1510. ;
  1511. Disp_56:
  1512.         mov     DI,29
  1513.         mov     cx,41
  1514.         call    One_String          ; display 'old' name
  1515. ;
  1516.         mov     DX,OFFSET STR56N
  1517.         mov     DI,DX
  1518.         add     DI,29
  1519.         push    DS
  1520.         mov     DS,[BP+REGES]
  1521.         mov     SI,[BP+REGDI]       ; get USER's ES:DI value
  1522.         mov     cx,41               ;  to display 'new' name
  1523. rep     movsb
  1524.         pop     DS
  1525.         mov     CX,0601h
  1526.         mov     BX,OFFSET W1
  1527.         mov     AH,HIWHITE
  1528.         call    WPrint
  1529.         ret
  1530.  
  1531. ;
  1532. ; Get Date and Time of File
  1533. ;
  1534. Disp_57:
  1535.         mov     AX,AXsave           ; user's AL has get/set indicator
  1536.         cmp     AL,00               ; is it GET?
  1537.         jz      gdtptr
  1538.         cmp     AL,01               ; is it SET?
  1539.         jz      sdtptr
  1540.         mov     DI,37               ; unknown function
  1541.         mov     AX,[BP+REGBX]       ; file handle
  1542.         call    OutWord
  1543.         ret
  1544. gdtptr:
  1545.         mov     DX,OFFSET STR57G
  1546.         jmp     SHORT ddtptr
  1547. ;
  1548. sdtptr:
  1549.         mov     DX,OFFSET STR57S
  1550. ddtptr:
  1551.         mov     DI,33
  1552.         mov     AX,[BP+REGBX]       ; BX register has file handle
  1553.         call    OutWord
  1554.         ret
  1555.  
  1556. ;
  1557. ; Lock/Unlock File
  1558. ;
  1559. Disp_5c:
  1560.         mov     AX,AXsave
  1561.         cmp     AL,00               ; 0 = Lock
  1562.         jz      dlck
  1563.         cmp     AL,01               ; 1 = Unlock
  1564.         jz      dunlck
  1565.         mov     DI,17
  1566.         mov     AX,[BP+REGBX]       ; BX has file handle
  1567.         call    OutWord
  1568.         ret
  1569. ;
  1570. dlck:
  1571.         mov     DX,OFFSET STR5c0
  1572.         mov     DI,10
  1573.         mov     AX,[BP+REGBX]
  1574.         call    OutWord
  1575.         ret
  1576. ;
  1577. dunlck:
  1578.         mov     DX,OFFSET STR5c1
  1579.         mov     DI,12
  1580.         mov     AX,[BP+REGBX]
  1581.         call    OutWord
  1582.         ret
  1583.  
  1584.  
  1585. ;
  1586. ; Table of function codes.
  1587. ; (1st) word is DOS function code (AH),
  1588. ; (2nd) word is pointer to string to display,
  1589. ; (3rd) word is subroutine address to handle display of this type function.
  1590. ;
  1591. FCtbl:
  1592.         dw      0000h, STR00, Disp_Str
  1593.         dw      0100h, STR01, Disp_Str
  1594.         dw      0200h, STR02, Disp_02
  1595.         dw      0300h, STR03, Disp_Str
  1596.         dw      0400h, STR04, Disp_04
  1597.         dw      0500h, STR05, Disp_05
  1598.         dw      0600h, STR06, Disp_06
  1599.         dw      0700h, STR07, Disp_Str
  1600.         dw      0800h, STR08, Disp_Str
  1601.         dw      0900h, STR09, Disp_09
  1602.         dw      0a00h, STR0a, Disp_0a
  1603.         dw      0b00h, STR0b, Disp_Str
  1604.         dw      0c00h, STR0c, Disp_0c
  1605.         dw      0d00h, STR0d, Disp_Str
  1606.         dw      0e00h, STR0e, Disp_0e
  1607.         dw      0f00h, STR0f, Disp_0f
  1608.         dw      1000h, STR10, Disp_10
  1609.         dw      1100h, STR11, Disp_11
  1610.         dw      1200h, STR12, Disp_12
  1611.         dw      1300h, STR13, Disp_13
  1612.         dw      1400h, STR14, Disp_14
  1613.         dw      1500h, STR15, Disp_15
  1614.         dw      1600h, STR16, Disp_16
  1615.         dw      1700h, STR17, Disp_17
  1616.         dw      1800h, STRUN, Disp_Str
  1617.         dw      1900h, STR19, Disp_Str
  1618.         dw      1a00h, STR1a, Disp_1a
  1619.         dw      1b00h, STR1b, Disp_Str
  1620.         dw      1c00h, STR1c, Disp_1c
  1621.         dw      1d00h, STRUN, Disp_Str
  1622.         dw      1e00h, STRUN, Disp_Str
  1623.         dw      1f00h, STRUN, Disp_Str
  1624.         dw      2000h, STRUN, Disp_Str
  1625.         dw      2100h, STR21, Disp_21
  1626.         dw      2200h, STR22, Disp_22
  1627.         dw      2300h, STR23, Disp_23
  1628.         dw      2400h, STR24, Disp_24
  1629.         dw      2500h, STR25, Disp_25
  1630.         dw      2600h, STR26, Disp_26
  1631.         dw      2700h, STR27, Disp_27
  1632.         dw      2800h, STR28, Disp_28
  1633.         dw      2900h, STR29, Disp_29
  1634.         dw      2a00h, STR2a, Disp_Str
  1635.         dw      2b00h, STR2b, Disp_2b
  1636.         dw      2c00h, STR2c, Disp_Str
  1637.         dw      2d00h, STR2d, Disp_2d
  1638.         dw      2e00h, STR2e, Disp_2e
  1639.         dw      2f00h, STR2f, Disp_Str
  1640.         dw      3000h, STR30, Disp_Str
  1641.         dw      3100h, STR31, Disp_Str
  1642.         dw      3200h, STRUN, Disp_Str
  1643.         dw      3300h, STR33, Disp_33
  1644.         dw      3400h, STRUN, Disp_Str
  1645.         dw      3500h, STR35, Disp_35
  1646.         dw      3600h, STR36, Disp_36
  1647.         dw      3700h, STR37, Disp_Str
  1648.         dw      3800h, STR38, Disp_Str
  1649.         dw      3900h, STR39, Disp_39
  1650.         dw      3a00h, STR3a, Disp_3a
  1651.         dw      3b00h, STR3b, Disp_3b
  1652.         dw      3c00h, STR3c, Disp_3c
  1653.         dw      3d00h, STR3d, Disp_3d
  1654.         dw      3e00h, STR3e, Disp_3e
  1655.         dw      3f00h, STR3f, Disp_3f
  1656.         dw      4000h, STR40, Disp_40
  1657.         dw      4100h, STR41, Disp_41
  1658.         dw      4200h, STR42, Disp_42
  1659.         dw      4300h, STR43, Disp_43
  1660.         dw      4400h, STR44, Disp_44
  1661.         dw      4500h, STR45, Disp_45
  1662.         dw      4600h, STR46, Disp_46
  1663.         dw      4700h, STR47, Disp_47
  1664.         dw      4800h, STR48, Disp_48
  1665.         dw      4900h, STR49, Disp_49
  1666.         dw      4a00h, STR4a, Disp_4a
  1667.         dw      4b00h, STR4b, Disp_4b
  1668.         dw      4c00h, STR4c, Disp_4c
  1669.         dw      4d00h, STR4d, Disp_Str
  1670.         dw      4e00h, STR4e, Disp_4e
  1671.         dw      4f00h, STR4f, Disp_Str
  1672.         dw      5000h, STRUN, Disp_Str
  1673.         dw      5100h, STRUN, Disp_Str
  1674.         dw      5200h, STRUN, Disp_Str
  1675.         dw      5300h, STRUN, Disp_Str
  1676.         dw      5400h, STR54, Disp_Str
  1677.         dw      5500h, STRUN, Disp_Str
  1678.         dw      5600h, STR56, Disp_56
  1679.         dw      5700h, STR57, Disp_57
  1680.         dw      5800h, STRUN, Disp_Str
  1681.         dw      5900h, STR59, Disp_Str
  1682.         dw      5a00h, STR5a, Disp_5a
  1683.         dw      5b00h, STR5b, Disp_5b
  1684.         dw      5c00h, STR5c, Disp_5c
  1685.         dw      5d00h, STRUN, Disp_Str
  1686.         dw      5e00h, STRUN, Disp_Str
  1687.         dw      5f00h, STRUN, Disp_Str
  1688.         dw      6000h, STRUN, Disp_Str
  1689.         dw      6100h, STRUN, Disp_Str
  1690.         dw      6200h, STR62, Disp_Str
  1691. LENFC   EQU     $ - FCtbl
  1692.  
  1693. ;
  1694. ; The XX's are just place holders for help in alignment during debugging
  1695. ;
  1696. STR00   db      'Terminate Program'
  1697.         db      0
  1698.  
  1699. STR01   db      'Keyboard Input With Echo'
  1700.         db      0
  1701.  
  1702. STR02   db      'Output Character  Hex XX  ASCII X'
  1703.         db      0
  1704.  
  1705. STR03   db      'Serial Input'
  1706.         db      0
  1707.  
  1708. STR04   db      'Serial Output     Hex XX  ASCII X'
  1709.         db      0
  1710.  
  1711. STR05   db      'Printer Output    Hex XX  ASCII X'
  1712.         db      0
  1713.  
  1714. STR06   db      'Direct Console I/O - '
  1715.         db      0
  1716.  
  1717. STR06I  db      'Input Character'
  1718.         db      0
  1719.  
  1720. STR07   db      'Direct Console Input Without Echo'
  1721.         db      0
  1722.  
  1723. STR08   db      'Console Input Without Echo'
  1724.         db      0
  1725.  
  1726. STR09   db      'Display String -->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1727.         db      'XXXXXXXXXXXL'
  1728.         db      0
  1729.  
  1730. STR0a   db      'Buffered Keyboard Input To XXXX:XXXXH'
  1731.         db      0
  1732.  
  1733. STR0b   db      'Check Standard Input Status'
  1734.         db      0
  1735.  
  1736. STR0c   db      'Clear Keyboard and Do Function XXH'
  1737.         db      0
  1738.  
  1739. STR0d   db      'Reset Disk'
  1740.         db      0
  1741.  
  1742. STR0e   db      'Select Disk XXH'
  1743.         db      0
  1744.  
  1745. STR0f   db      'Open File Using FCB at XXXX:XXXXH'
  1746.         db      0
  1747.  
  1748. STR10   db      'Close File Using FCB at XXXX:XXXXH'
  1749.         db      0
  1750.  
  1751. STR11   db      'Search For First Matching File Using FCB at XXXX:XXXXH'
  1752.         db      0
  1753.  
  1754. STR12   db      'Search For Next Matching File Using FCB at XXXX:XXXXH'
  1755.         db      0
  1756.  
  1757. STR13   db      'Delete File Using FCB at XXXX:XXXXH'
  1758.         db      0
  1759.  
  1760. STR14   db      'Read Sequential File Record Using FCB at XXXX:XXXXH'
  1761.         db      0
  1762.  
  1763. STR15   db      'Write Sequential File Record Using FCB at XXXX:XXXXH'
  1764.         db      0
  1765.  
  1766. STR16   db      'Create File Using FCB at XXXX:XXXXH'
  1767.         db      0
  1768.  
  1769. STR17   db      'Rename File Using FCB at XXXX:XXXXH'
  1770.         db      0
  1771.  
  1772. STR19   db      'Report Current Drive'
  1773.         db      0
  1774.  
  1775. STR1a   db      'Set Disk Transfer Address To XXXX:XXXXH'
  1776.         db      0
  1777.  
  1778. STR1b   db      'Get FAT Information For Default Drive'
  1779.         db      0
  1780.  
  1781. STR1c   db      'Get FAT Information For Drive XXH'
  1782.         db      0
  1783.  
  1784. STR21   db      'Read Random File Record Using FCB at XXXX:XXXXH'
  1785.         db      0
  1786.  
  1787. STR22   db      'Write Random File Record Using FCB at XXXX:XXXXH'
  1788.         db      0
  1789.  
  1790. STR23   db      'Get File Size Using FCB at XXXX:XXXXH'
  1791.         db      0
  1792.  
  1793. STR24   db      'Set Random Record Field Using FCB at XXXX:XXXXH'
  1794.         db      0
  1795.  
  1796. STR25   db      'Set Interrupt Vector XXH to XXXX:XXXXH'
  1797.         db      0
  1798.  
  1799. STR26   db      'Create New Program Segment At Segment XXXXH'
  1800.         db      0
  1801.  
  1802. STR27   db      'Read XXXXH Random File Records Using FCB at XXXX:XXXXH'
  1803.         db      0
  1804.  
  1805. STR28   db      'Write XXXXH Random File Records Using FCB at XXXX:XXXXH'
  1806.         db      0
  1807.  
  1808. STR29   db      'Parse Filename -->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1809.         db      'XXXXXXXXXXXL'
  1810.         db      0
  1811.  
  1812. STR2a   db      'Get Date'
  1813.         db      0
  1814.  
  1815. STR2b   db      'Set Date To mm/dd/yy  XX/XX/XX'
  1816.         db      0
  1817.  
  1818. STR2c   db      'Get Time'
  1819.         db      0
  1820.  
  1821. STR2d   db      'Set Time To Hrs:Mins:Secs:Hunds  XX:XX:XX:XX'
  1822.         db      0
  1823.  
  1824. STR2e   db      'Set Disk Write Verification XXX'
  1825.         db      0
  1826.  
  1827. STR2f   db      'Get Disk Transfer Address'
  1828.         db      0
  1829.  
  1830. STR30   db      'Get DOS Version Number'
  1831.         db      0
  1832.  
  1833. STR31   db      'Terminate Process and Remain Resident'
  1834.         db      0
  1835.  
  1836. STR33   db      'Get/Set Control-Break Status'
  1837.         db      0
  1838.  
  1839. STR33G  db      'Get Control-Break Status'
  1840.         db      0
  1841.  
  1842. STR33S  db      'Set Control-Break Status XXX'
  1843.         db      0
  1844.  
  1845. STR35   db      'Get Interrupt Vector XXH'
  1846.         db      0
  1847.  
  1848. STR36   db      'Get Disk Free Space On Drive XXH'
  1849.         db      0
  1850.  
  1851. STR37   db      'Get DOS Switch Character'
  1852.         db      0
  1853.  
  1854. STR38   db      'Get/Set Country Dependent Information'
  1855.         db      0
  1856.  
  1857. STR39   db      'Create Subdir --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1858.         db      'XXXXXXXXXXXL'
  1859.         db      0
  1860.  
  1861. STR3a   db      'Remove Subdir --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1862.         db      'XXXXXXXXXXXL'
  1863.         db      0
  1864.  
  1865. STR3b   db      'Change Dir To --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1866.         db      'XXXXXXXXXXXL'
  1867.         db      0
  1868.  
  1869. STR3c   db      'Create File ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1870.         db      'XXXXXXXXXXXL'
  1871.         db      0
  1872.  
  1873. STR3d   db      'Open File ------->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1874.         db      'XXXXXXXXXXXL'
  1875.         db      0
  1876.  
  1877. STR3e   db      'Close File Handle XXXXH'
  1878.         db      0
  1879.  
  1880. STR3f   db      'Read XXXXH Bytes From File or Device XXXXH'
  1881.         db      0
  1882.  
  1883. STR40   db      'Write XXXXH Bytes To File or Device XXXXH'
  1884.         db      0
  1885.  
  1886. STR41   db      'Delete File ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1887.         db      'XXXXXXXXXXXL'
  1888.         db      0
  1889.  
  1890. STR42   db      'Move File Handle XXXXH Pointer By XXXX:XXXXH From '
  1891.         db      'XXXXXXXXXXXXXXXXX'
  1892.         db      0
  1893.  
  1894. STR43   db      'Get/Set File Attributes'
  1895.         db      0
  1896.  
  1897. STR43G  db      'Get File Attrib ->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1898.         db      'XXXXXXXXXXXX'
  1899.         db      0
  1900.  
  1901. STR43S  db      'Set File Attrib ->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1902.         db      'XXXXXXXXXXXX'
  1903.         db      0
  1904.  
  1905. STR44   db      'I/O Control For Devices'
  1906.         db      0
  1907.  
  1908. STR440  db      'Get Info For Device XXXXH'
  1909.         db      0
  1910.  
  1911. STR441  db      'Set Info For Device XXXXH to XXXXH'
  1912.         db      0
  1913.  
  1914. STR442  db      'Read XXXXH Bytes From Drive Control Channel of File XXXXH'
  1915.         db      0
  1916.  
  1917. STR443  db      'Write XXXXH Bytes To Drive Control Channel of File XXXXH'
  1918.         db      0
  1919.  
  1920. STR444  db      'Read XXXXH Bytes From Control Channel of Drive XXH'
  1921.         db      0
  1922.  
  1923. STR445  db      'Write XXXXH Bytes To Control Channel of Drive XXH'
  1924.         db      0
  1925.  
  1926. STR446  db      'Get Input Status of Device XXXXH'
  1927.         db      0
  1928.  
  1929. STR447  db      'Get Output Status of Device XXXXH'
  1930.         db      0
  1931.  
  1932. STR448  db      'Report Whether Device XXXXH Has Removable Media'
  1933.         db      0
  1934.  
  1935. STR4411 db      'Set Retries For Device XXXXH to XXXXH With Interval of XXXXH'
  1936.         db      0
  1937.  
  1938. STR45   db      'Duplicate File Handle XXXXH'
  1939.         db      0
  1940.  
  1941. STR46   db      'Force Duplication of Handle XXXXH to XXXXH'
  1942.         db      0
  1943.  
  1944. STR47   db      'Get Current Directory of Drive XXH into XXXX:XXXXH'
  1945.         db      0
  1946.  
  1947. STR48   db      'Allocate XXXXH Paragraphs of Memory'
  1948.         db      0
  1949.  
  1950. STR49   db      'Free Allocated Memory at Segment XXXXH'
  1951.         db      0
  1952.  
  1953. STR4a   db      'Modify Memory Block at Segment XXXXH to be XXXXH Paragraphs'
  1954.         db      0
  1955.  
  1956. STR4b   db      'Load or Execute Program ---->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1957.         db      'XXXXXXXXXXXX'
  1958.         db      0
  1959.  
  1960. STR4c   db      'Terminate Process With Return Code XXH'
  1961.         db      0
  1962.  
  1963. STR4d   db      'Get Return Code of Subprocess'
  1964.         db      0
  1965.  
  1966. STR4e   db      'Find First Matching File --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1967.         db      'XXXXXXXXXXXX'
  1968.         db      0
  1969.  
  1970. STR4f   db      'Find Next Matching File'
  1971.         db      0
  1972.  
  1973. STR54   db      'Get Verify State'
  1974.         db      0
  1975.  
  1976. STR56   db      'Rename File   Old Name ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1977.         db      'XXXXXXXXXXXX'
  1978.         db      0
  1979.  
  1980. STR56N  db      '              New Name ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1981.         db      'XXXXXXXXXXXX'
  1982.         db      0
  1983.  
  1984. STR57   db      'Get/Set Date and Time of File Handle XXXXH'
  1985.         db      0
  1986.  
  1987. STR57G  db      'Get Date and Time of File Handle XXXXH'
  1988.         db      0
  1989.  
  1990. STR57S  db      'Set Date and Time of File Handle XXXXH'
  1991.         db      0
  1992.  
  1993. STR59   db      'Get Extended Error Code'
  1994.         db      0
  1995.  
  1996. STR5a   db      'Create Temp File  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  1997.         db      'XXXXXXXXXXXL'
  1998.         db      0
  1999.  
  2000. STR5b   db      'Create New File   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
  2001.         db      'XXXXXXXXXXXL'
  2002.         db      0
  2003.  
  2004. STR5c   db      'Lock/Unlock File XXXXH'
  2005.         db      0
  2006.  
  2007. STR5c0  db      'Lock File XXXXH'
  2008.         db      0
  2009.  
  2010. STR5c1  db      'Unlock File XXXXH'
  2011.         db      0
  2012.  
  2013. STR62   db      'Get PSP Address'
  2014.         db      0
  2015.  
  2016. STRUN   db      '** Undocumented Function Code **'
  2017.         db      0
  2018.  
  2019. ;
  2020. ; Don't change the size of the following strings
  2021. ;
  2022. Blanks3  db      '   '
  2023. Blanks17 db      '                 '
  2024. ONstr    db      'ON '
  2025. OFFstr   db      'OFF'
  2026. BOFstr   db      'Beginning of File'
  2027. CURstr   db      'Current Location '
  2028. EOFstr   db      'End of File      '
  2029.  
  2030.  
  2031. Open_Window:
  2032.         push    ES
  2033.         mov     BX,OFFSET W1        ; window parameters
  2034. ;
  2035. ; Save current contents of window area
  2036. ;
  2037.         mov     SI,[BX].startmem    ; screen addr of start of window
  2038.         mov     DX,[BX].height
  2039.         mov     ES,Winseg           ; point to allocated memory block
  2040.         mov     DI,0000
  2041. saverow:
  2042.         push    DS
  2043.         mov     CX,[BX].xwidth
  2044.         mov     DS,Scrseg           ; get screen segment
  2045.         push    SI                  ; save screen offset
  2046. rep     movsw                       ; do word to get char and attribute
  2047.         pop     SI
  2048.         pop     DS
  2049.         add     SI,BytesPL          ; next row down
  2050.         dec     DX
  2051.         jnz     saverow
  2052. ;
  2053. ; Draw window
  2054. ;
  2055.         mov     ES,Scrseg           ; get screen segment
  2056.         mov     DI,[BX].startmem    ; physical addr of start of window
  2057.         mov     AH,HIWHITE
  2058. ;
  2059. ; Draw top border
  2060. ;
  2061.         push    DI
  2062.         mov     AL,ULC              ; write upper left corner
  2063.         stosw
  2064.         mov     CX,[BX].xwidth
  2065.         sub     CX,2
  2066.         mov     AL,BRDROW
  2067. rep     stosw
  2068.         mov     AL,URC              ; write upper right corner
  2069.         stosw
  2070.         pop     DI
  2071.         add     DI,BytesPL          ; next row down
  2072. ;
  2073. ; Draw middle of window
  2074. ;
  2075.         mov     DX,[BX].height
  2076.         sub     DX,2
  2077. winrows:
  2078.         push    DI
  2079.         mov     AL,BRDCOL           ; left border column
  2080.         stosw
  2081.         mov     CX,[BX].xwidth
  2082.         sub     CX,2
  2083.         mov     AL,BLANK
  2084. rep     stosw
  2085.         mov     AL,BRDCOL           ; right border column
  2086.         stosw
  2087.         pop     DI
  2088.         add     DI,BytesPL          ; next row down
  2089.         dec     DX
  2090.         jnz     winrows
  2091. ;
  2092. ; Draw bottom border
  2093. ;
  2094.         push    DI
  2095.         mov     AL,LLC              ; write lower left corner
  2096.         stosw
  2097.         mov     CX,[BX].xwidth
  2098.         sub     CX,2
  2099.         mov     AL,BRDROW
  2100. rep     stosw
  2101.         mov     AL,LRC              ; write lower right corner
  2102.         stosw
  2103.         pop     DI
  2104.         pop     ES
  2105.         ret
  2106.  
  2107.  
  2108. Close_Window:
  2109.         mov     BX,OFFSET W1
  2110.         mov     DI,[BX].startmem    ; physical addr of screen area
  2111.         mov     ES,Scrseg           ; point to allocated memory block
  2112.         mov     SI,0000             ; start of save memory block
  2113.         mov     DX,[BX].height
  2114. resrow:
  2115.         push    DS
  2116.         mov     CX,[BX].xwidth
  2117.         mov     DS,Winseg           ; get saved memory segment
  2118.         push    DI                  ; save screen offset
  2119. rep     movsw                       ; do word to get char and attribute
  2120.         pop     DI
  2121.         pop     DS
  2122.         add     DI,BytesPL          ; next row down
  2123.         dec     DX
  2124.         jnz     resrow
  2125.         ret
  2126.  
  2127. ;
  2128. ; Print a string in window.
  2129. ; Entry:
  2130. ;        CX = Row, Col position relative to start of window
  2131. ;        BX = Window pointer
  2132. ;        AH = Attribute
  2133. ;        DX = addr of string
  2134. ;
  2135. WPrint:
  2136.         push    ES
  2137.         call    GetRC               ; convert to row, col in DI
  2138.         mov     ES,Scrseg
  2139.         mov     SI,DX               ; move string address
  2140. wpwrt:
  2141.         cmp     BYTE PTR [SI],00    ; test for string terminator <NULL>
  2142.         jz      wpexit
  2143.         lodsb
  2144.         stosw
  2145.         jmp     wpwrt
  2146. wpexit:
  2147.         pop     ES
  2148.         ret
  2149.  
  2150. ;
  2151. ; Write one character and attribute to window
  2152. ;
  2153. ; Entry:
  2154. ;        CX = Row, Col position relative to start of window
  2155. ;        BX = Window pointer
  2156. ;        AH = attr
  2157. ;        AL = char
  2158. ;
  2159. WChar:
  2160.         push    ES
  2161.         call    GetRC               ; convert to row, col in DI
  2162.         mov     ES,Scrseg
  2163.         stosw
  2164.         pop     ES
  2165.         ret
  2166.  
  2167. ;
  2168. ; Convert row, col in CX to physical addr in DI
  2169. ;
  2170. GetRC:
  2171.         push    AX
  2172.         push    DX
  2173.         mov     DI,[BX].startmem    ; physical start of window memory
  2174.         add     DI,BytesPL          ; go down a row
  2175.         add     DI,2                ; go in one char, this is 0,0
  2176.         mov     AL,CH
  2177.         xor     AH,AH               ; AX = relative row number
  2178.         mul     BytesPL             ; this clobbers DX
  2179.         add     DI,AX
  2180.         mov     AX,CX               ; restore coordinates
  2181.         xor     AH,AH               ; AX = relative col number
  2182.         shl     AX,1                ; times 2 for attribute
  2183.         add     DI,AX
  2184.         pop     DX
  2185.         pop     AX
  2186.         ret
  2187.  
  2188. ;
  2189. ; WRITE HEX WORD
  2190. ; Convert a hex word to an ASCII string and display it
  2191. ; Entry:
  2192. ;        CX = Row, Col position relative to start of window
  2193. ;        BX = Window pointer
  2194. ;        AX = Word to convert
  2195. ;
  2196. Whexwd:
  2197.         push    AX
  2198.         push    BX
  2199.         push    CX
  2200.         push    DX
  2201. ;
  2202.         push    BX                  ; save window pointer
  2203.         push    CX                  ;  and row, col
  2204.         mov     DI,OFFSET Astr
  2205.         xchg    AH,AL
  2206.         call    Shexbyt
  2207.         xchg    AH,AL
  2208.         call    Shexbyt
  2209.         xor     AL,AL
  2210.         stosb                       ; make sure of terminating NULL
  2211.         mov     DX,OFFSET Astr
  2212.         pop     CX                  ; get row, col
  2213.         pop     BX                  ;  and Window ptr
  2214.         mov     AH,HIWHITE          ; set attribute
  2215.         call    WPrint
  2216. ;
  2217.         pop     DX
  2218.         pop     CX
  2219.         pop     BX
  2220.         pop     AX
  2221.         ret
  2222.  
  2223. ;
  2224. ; STORE HEX WORD
  2225. ; Convert a hex word to ASCII and store it in destination string
  2226. ; Entry:
  2227. ;        AX = Word to convert
  2228. ;        DI = destination pointer
  2229. ;
  2230. Shexwrd:
  2231.         xchg    AL,AH               ; convert upper half first
  2232.         call    Shexbyt
  2233.         xchg    AL,AH               ; convert lower half
  2234.         call    Shexbyt
  2235.         ret
  2236.  
  2237. ;
  2238. ; STORE HEX BYTE
  2239. ; Convert a hex byte to ASCII and store it in destination string
  2240. ; Entry:
  2241. ;        AL = Byte to convert
  2242. ;        DI = destination pointer
  2243. ;
  2244. Shexbyt:
  2245.         push    AX
  2246.         mov     AH,AL               ; save temporarily
  2247.         shr     AL,1
  2248.         shr     AL,1
  2249.         shr     AL,1
  2250.         shr     AL,1
  2251.         cmp     AL,10
  2252.         jb      wh1
  2253.         add     AL,07
  2254. wh1:
  2255.         add     AL,'0'
  2256.         stosb
  2257.         mov     AL,AH
  2258.         and     AL,0fh
  2259.         cmp     AL,10
  2260.         jb      wh2
  2261.         add     AL,07
  2262. wh2:
  2263.         add     AL,'0'
  2264.         stosb
  2265.         pop     AX
  2266.         ret
  2267.  
  2268. ;
  2269. ; Check if key pressed requires special handling
  2270. ;
  2271. ; Entry:
  2272. ;      AX = key pressed
  2273. ;
  2274. Disp_Key:
  2275.         mov     DI,OFFSET Keytbl    ; keys and subroutine addresses
  2276.         mov     CX,LENKTAB / 4      ; number of entries
  2277. cmpdk:
  2278.         cmp     AX,[DI]             ; is key in table?
  2279.         jz      dkexec
  2280.         add     DI,4                ; no, point to next key value
  2281.         loop    cmpdk
  2282.         ret
  2283. dkexec:
  2284.         add     DI,2
  2285.         call    [WORD PTR DI]
  2286.         ret
  2287.  
  2288. ;
  2289. ; Table of keys to watch for followed by the address of the routine to execute
  2290. ;
  2291. Keytbl  dw      ESCAPE,  DO_Esc
  2292.         dw      BIGS,    Do_Skey
  2293.         dw      SMALLS,  Do_Skey
  2294.         dw      BIGR,    Do_Rkey
  2295.         dw      SMALLR,  Do_Rkey
  2296. LENKTAB EQU     $ - Keytbl
  2297.  
  2298. ;
  2299. ; If ESC key, clear 'running flag' so Int 21h will not be stopped each time
  2300. ;
  2301. Do_Esc:
  2302.         mov     AL,00
  2303.         mov     Run_Flg,AL
  2304.         ret
  2305.  
  2306. ;
  2307. ; 'S' key - skip successive functions of current type.
  2308. ; Return to intercepting calls when something new comes along.
  2309. ; This is so you don't have to sit through dozens if Function '2' calls
  2310. ; while the target program outputs a string to the display.
  2311. ;
  2312. Do_Skey:
  2313.         mov     AL,0ffh
  2314.         mov     Skip_Flg,AL         ; set flag to show we should skip something
  2315.         mov     AX,AXsave           ; get current function code
  2316.         mov     Skip_Typ,AH         ; save it
  2317.         ret
  2318.  
  2319. ;
  2320. ; 'R' key - stop after INT 21h call and let user see result registers
  2321. ;
  2322. Do_Rkey:
  2323.         mov     AL,0ffh
  2324.         mov     Ret_Flg,AL          ; set flag
  2325.         ret
  2326.  
  2327. ;
  2328. ; Wait for any key pressed
  2329. ;
  2330. Get_Key:
  2331.         mov     AH,00
  2332.         int     16h
  2333.         ret
  2334.  
  2335. XTest:
  2336.         mov     AH,02               ; write char
  2337.         mov     DL,07               ; <BELL>
  2338.         int     21h
  2339.         iret
  2340.  
  2341. ;
  2342. ; Define format of WINDOW structure
  2343. ;
  2344. Window  STRUC
  2345.    leftrow   dw     ?
  2346.    leftcol   dw     ?
  2347.    rightrow  dw     ?
  2348.    rightcol  dw     ?
  2349.    xwidth    dw     ?
  2350.    height    dw     ?
  2351.    startmem  dw     ?
  2352. Window  ENDS
  2353.  
  2354. ;
  2355. ; Allocate and intialize WINDOW parameters
  2356. ;
  2357. W1       Window     <8, 2, 18, 74, 0, 0, 0>
  2358.  
  2359. Winseg    dw     0000                ; store segment of allocated memory
  2360.                                      ;  for saving screen data
  2361. Scrseg    dw     0b800h              ; segment where screen memory can be found
  2362. BytesPL   dw     80*2                ; number of bytes per line (char + attr)
  2363. Run_Flg   db     0ffh                ; 'running' flag
  2364. Ret_Flg   db     00                  ; 'stop on return' flag
  2365. ;
  2366. ; The following two variables are initialized the way they are to skip
  2367. ; the first Int 21 call generated by 'STEPDOS' to EXEC the target program.
  2368. ;
  2369. Skip_Typ db     4bh                 ; type of function call to skip temporarily
  2370. Skip_Flg db     0ffh                ; set if function should be skipped
  2371.  
  2372. Save21   dw     ?                   ; save original Int21 vector here, IP
  2373.          dw     ?                   ;  and SEG
  2374.  
  2375. Ssave    LABEL  DWORD
  2376. SPsave   dw     ?                   ; save some of the user's registers here
  2377. SSsave   dw     ?                   ;  others will be on local stack
  2378.  
  2379. AXsave   dw     ?                   ; these will have been left on user's
  2380. DSsave   dw     ?                   ;  stack instead of local stack
  2381. CSsave   dw     ?
  2382. IPsave   dw     ?
  2383. FLsave   dw     ?
  2384. ;
  2385. ; Parameter block that will be passed to the EXEC function call (4bh) of DOS
  2386. ;
  2387. Param_Block     LABEL  WORD
  2388. SegEnv   dw     ?                   ; segment addr of environment string
  2389. SegCmd   dw     ?                   ; segmented ptr to command line
  2390.          dw     ?
  2391. FCBptr1  dw     ?                   ; segmented ptr to first FCB
  2392.          dw     ?
  2393. FCBptr2  dw     ?                   ; segmented ptr to second FCB
  2394.          dw     ?
  2395.  
  2396. ;
  2397. ; File name that will be passed to the EXEC function call of DOS
  2398. ;
  2399. Filename db     128 dup (0)
  2400. FNsize   dw     0
  2401. ;
  2402. ; Command line from PSP:80h will be copied to here work from
  2403. ;
  2404. PSPstr   db     128 dup (0)
  2405.  
  2406. ;
  2407. ; Command Line that will be passed to the EXEC function call of DOS
  2408. ;
  2409. CLstr    db     128 dup (0)
  2410.  
  2411. ;
  2412. ; Two FCB's that will be passed to the EXEC function call of DOS
  2413. ;
  2414. FCB1     db     0
  2415.          db     11 dup (' ')
  2416.          db     0, 0, 0, 0
  2417.  
  2418. FCB2     db     0
  2419.          db     11 dup (' ')
  2420.          db     0, 0, 0, 0
  2421.  
  2422. COMstr  db      '.COM'
  2423. EXEstr  db      '.EXE'
  2424. ;
  2425. INITmsg  db     'STEPDOS Version 1.0'
  2426.          db     CR
  2427.          db     LF
  2428.          db     '$'
  2429.  
  2430. Memerr   db     CR
  2431.          db     LF
  2432.          db     'Error Allocating Window Memory$'
  2433.  
  2434. Execmsg  db     CR
  2435.          db     LF
  2436.          db     'Unable to execute target program$'
  2437.  
  2438. Findmsg  db     CR
  2439.          db     LF
  2440.          db     'Unable to find target program$'
  2441.  
  2442. Umsg     db     CR
  2443.          db     LF
  2444.          db     'Usage: STEPDOS <filename>$'
  2445.  
  2446. RegStr1  db     ' AX   BX   CX   DX   DI   SI   BP   SP'
  2447.          db     '   DS   ES   SS   CS   IP   FL'
  2448.          db     0
  2449.  
  2450. RegStr2  db     '---- ---- ---- ---- ---- ---- ---- ----'
  2451.          db     ' ---- ---- ---- ---- ---- ----'
  2452.          db     0
  2453.  
  2454. HlpStr1  db     'kip Current Function'
  2455.          db     0
  2456.  
  2457. HlpStr2  db     'eturn Code'
  2458.          db     0
  2459.  
  2460. HlpStr3  db     ' - Non Stop'
  2461.          db     0
  2462.  
  2463. HlpStr4  db     'Press Any Key To Continue'
  2464.          db     0
  2465.  
  2466. Astr     db     32 dup (0)          ; string for converting ASCII characters
  2467.  
  2468. ;
  2469. ; Local Program Stack Area
  2470. ;
  2471.          db     128 dup (?)
  2472. Pstack   EQU    $
  2473.  
  2474. ;
  2475. ; Target Stack Area
  2476. ;
  2477.          db     128 dup (?)
  2478. Tstack   EQU    $
  2479.  
  2480.  
  2481. IF TESTING
  2482.  
  2483. Istr     db     128 dup (' ')
  2484.  
  2485. Ostr     db     'Output String'
  2486.          db     0
  2487. ENDIF
  2488.  
  2489.  
  2490. IF TESTING
  2491.         cli
  2492.         mov     AX,0
  2493.         mov     ES,AX
  2494.         mov     AX,OFFSET XTest
  2495.         mov     ES:[INT21OFF],AX
  2496.         mov     ES:[INT21OFF+2],CS
  2497.         sti
  2498. ENDIF
  2499.  
  2500. IF TESTING
  2501.         include test.asm
  2502.         jmp     execdn
  2503. ELSE
  2504.         int     21h
  2505. ENDIF
  2506.  
  2507. Code    ENDS
  2508.  
  2509.         END     Main
  2510.  
  2511.